﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using FasterWPF.Selectors;

namespace FasterWPF
{
    #region ISortArgs

    public class TreeViewSort : FasterWPF.CommonExt.ISortArgs
    {
        public TreeViewSort(CommonExt.SortDataType sortDataType)
        {
            SortDataType = sortDataType;
        }

        public TreeViewSort(CommonExt.SortDataType sortDataType, CommonExt.SortDataType sortDataType2)
        {
            SortDataType = sortDataType;
            SortDataType2 = sortDataType2;
        }

        public CommonExt.SortDataType SortDataType
        {
            get;
            set;
        }

        public CommonExt.SortDataType SortDataType2
        {
            get;
            set;
        }
    }

    #endregion

    public class TreeViewArgs
    {
        public string  Guid
        {
            get;
            set;
        }

        //leave Level out for now
        public TreeViewArgs(string key)
        {
            Guid = key;
        }
    }

    public class TreeViewParent : FasterWPF.IParent, ICanSort, FasterWPF.IScrollViewerStrategy
    {         
        //this is ANA?
        public object Generate<T>(object chain, T args, Action<ContentControl> addUIElementsAction)
        {
            return chain;
        }

        #region IParent

        //this is BIND
        public object Add<T>(object chain, string key, T args, Border itemToAdd)
        {
            TreeView t = (TreeView)chain;

            //set these here to allow overriding the default values
            ScrollViewerExt.SetCanContentScroll<FrameworkElement>((FrameworkElement)chain);
            //ScrollViewerExt.SetVerticalPageUpButtonDelayAndInterval<FrameworkElement>((FrameworkElement)chain);
            
            TreeViewItem newChild = new TreeViewItem();
            newChild.Header = itemToAdd;
            
            if (args is TreeViewArgs)
            {
                //if Guid of Parent Node has been supplied, add as a Child to the Parent Node
                if ( (args as TreeViewArgs).Guid!= null)
                {
                    ((TreeViewItem)(t.GetCompositeFromParent<TreeView>((args as TreeViewArgs).Guid)).Parent).Items.Add(newChild);
                }
                else  //this is a Parent Node. Just add it. Mark it as Level_1
                {
                     t.Items.Add(newChild);
                     itemToAdd.SetValue(SelectorClassSetting.SelectorClass1Property, "Level_1");
                }
            }
//TreeView1.Items.Add(newChild);

//TreeViewItem newSubChild = new TreeViewItem();
//newSubChild.Header = "SubItem";
//newChild.Items.Add(newSubChild);

//TreeViewItem newSubSubChild = new TreeViewItem();
//newSubSubChild.Header = "SubSubItem";
//newSubChild.Items.Add(newSubSubChild);

            return chain;
        }

        public void Remove(object chain, string key, Border itemToRemove)
        {
            ((TreeView)chain).Items.Remove(itemToRemove.Parent as TreeViewItem); //remove from TreeView

            IComposite ic = (IComposite)(((TreeView)chain).GetIComposite<TreeView>());
            ic.RemoveFromChain(itemToRemove);
        }

        public Dictionary<string, object> RetrieveDictionary(object chain)
        {
            return ((TreeView)chain).GetCompositeLookupDictionary<TreeView>();
        }

        //this is CATA?
        public List<Border> RetrieveCollection(object chain)
        {
            List<Border> lb = new List<Border>();
            foreach (var kvp in ((TreeView)chain).GetCompositeLookupDictionary<TreeView>())
            {
                lb.Add((Border)kvp.Value);
            }

            return lb;
        }

        #endregion

        #region ICanSort

        public void ClearCollection(object chain)
        {
            IParent currentComposite = ((TreeView)chain).GetSetting<TreeView, IParent>("IParent");
            List<Border> gridItems = currentComposite.RetrieveCollection(chain);

            foreach (Border borItem in gridItems)
            {
                if (Selectors.Select.IsInSelectorClassProperties(borItem, "Level_1"))
                {
                    ((TreeView)chain).Items.Remove(borItem.Parent as TreeViewItem); //remove from TreeView
                }
            }
        }

        public void BeforeSortCollection<T>(object chain, object args, int row, int column, CommonExt.SortOrder sortOrder, CommonExt.SortControlType sortControlType)
            where T : FrameworkElement
        {
            char underscore = '_';
            var orderedKeys = ((TreeView)chain).GetOrderedKeyList();
            var rows = ((TreeView)chain).GetCompositeLookupDictionary();
            Dictionary<string, object> ChildLookupDict = new Dictionary<string, object>();

            //Create a ChildLookupDictionary Filtered by Level 1 - only the children directly tied to the parent level of nodes in the TreeView, excluding the children tied to child nodes
            var tempChildList = ((TreeView)chain).GetChildLookupDictionary().Where(kvp => { 
           //From the Child (via splitting its Key), get Parent Composite and check Class to see whether it is a Level 1 (Parent Node)
                return Selectors.Select.IsInSelectorClassProperties((((TreeView)chain).GetCompositeFromCompositeLookupDictionary<TreeView>(kvp.Key.Split(underscore)[0]) as Border), "Level_1");
            });

            foreach (KeyValuePair<string, object> keyPair in tempChildList)
            {
                ChildLookupDict.Add(keyPair.Key, keyPair.Value);
            }

            //Retrieve all the Composites and Order them by Ordered Key List
            IParent currentComposite = ((TreeView)chain).GetSetting<TreeView, IParent>("IParent");
            List<Border> gridItemsUnOrdered = currentComposite.RetrieveCollection(chain);
            List<Border> gridItems = new List<Border>();
            foreach (string s in orderedKeys)
            {
                gridItems.Add(gridItemsUnOrdered.Where(b => { return b.GetKey() == s; }).First());
            }

            List<int> initialOrderCol = new List<int>();
            List<int> initialOrderRow = new List<int>();
            List<string> initialOrderKey = new List<string>();

            foreach (Border borK in gridItems)
            {
                initialOrderKey.Add(borK.GetKey());
            }

            if (gridItems != null && gridItems.Count > 0)
            {
                ClearCollection(chain);

                orderedKeys.Clear();

                IEnumerable<string> items = null;

                if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.DateTime)
                {
                    items = CommonInternalExt.PerformSortOfKeysLevelOneDateTime<T>(row, column, sortOrder, ChildLookupDict, items, sortControlType);
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.Decimal)
                {
                    items = CommonInternalExt.PerformSortOfKeysLevelOneDecimal<T>(row, column, sortOrder, ChildLookupDict, items, sortControlType);
                }
                else if (args is FasterWPF.CommonExt.ISortArgs && (((FasterWPF.CommonExt.ISortArgs)args).SortDataType) == FasterWPF.CommonExt.SortDataType.Integer)
                {
                    items = CommonInternalExt.PerformSortOfKeysLevelOneInteger<T>(row, column, sortOrder, ChildLookupDict, items, sortControlType);
                }
                else
                {
                    //Default to String
                    items = CommonInternalExt.PerformSortOfKeysLevelOne<T>(row, column, sortOrder, ChildLookupDict, items, sortControlType);
                }

                List<string> itemsToList = items.ToList();

                IterHelpers.ApplyLoop(itemsToList.Count, j =>
                {
                    String tempKey = (string)itemsToList[j];
                    Border tempBorder = gridItems[initialOrderKey.FindIndex(str => { return str == tempKey; })];
                    orderedKeys.Add(tempKey);

                    //Re-Add the Keys of All Child Composites as well
                    foreach (TreeViewItem tviChild in ((TreeViewItem)(tempBorder).Parent).Items)
                    {
                        orderedKeys.Add((tviChild.Header as Border).GetKey());
                    }

                    ((TreeView)chain).Items.Add(tempBorder.Parent as TreeViewItem);
                });
            } 
        }

        public void BeforeSortCollection1Then2<T>(object chain, object args, int row, int column, int row2, int column2, CommonExt.SortOrder sortOrder, CommonExt.SortOrder sortOrder2, CommonExt.SortControlType sortControlType) where T : FrameworkElement
        {
        
        }

        public void AfterSortCollection<T>(object chain)
             where T : FrameworkElement
        { }

        public void InnerSortCollection(object chain, int row, int column, string key, ref int counter, Border itemToReAdd)
        {
            //Hmm, record original order in which they were added?

            //re-add in the same pattern of x-y coordinates, making sure to NULL-check?!?

            throw new NotImplementedException();
        }

        #endregion

        #region ICanSelect

        public void SetSelected(object chain, Border itemToSetAsSelected)
        {
        }

        #endregion

        #region IScrollViewerStrategy

        public ScrollViewer GetScrollViewer(object chain)
        {
            TreeView trv = (TreeView)chain;
            var builtCheck = trv.ApplyTemplate();
            Border bd = (Border)trv.Template.FindName("Bd", trv);

            var settings = trv.GetSettingsDictionary();

            if (settings.Keys.Contains("ScrollViewerPadding"))
            {
                bd.Padding = (Thickness)settings["ScrollViewerPadding"];
            }
            else
            {
                bd.Padding = new Thickness(0); //default to zero
            }
            ScrollViewer svw = bd.Child.Cast<ScrollViewer>();

            return svw;
        }

        public T GetParentContainerFromScrollViewerThumb<T>(System.Windows.Controls.Primitives.Thumb myThumb)
        {
            T source = ((Border)((ScrollViewer)
                ((Grid)
                ((ScrollBar)myThumb.TemplatedParent).Parent).TemplatedParent
                ).Parent).TemplatedParent.Cast<T>();
            return source;
        }

        #endregion
    }
}
